<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta http-equiv="Cache-Control" content="no-siteapp">
  <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
  <meta name="renderer" content="webkit">

  
  <title>Android10.0 人脸解锁流程分析 | 龙之叶的博客</title>

  <link rel="shortcut icon" href="/images/favicon.png">
  <link rel="alternate" href="/atom.xml" title="龙之叶的博客" type="application/atom+xml">
  <meta name="description" content="Android10.0 人脸解锁流程分析">
<meta property="og:type" content="article">
<meta property="og:title" content="Android10.0 人脸解锁流程分析">
<meta property="og:url" content="http://longzhiye.top/2023/12/10/2023-12-10/index.html">
<meta property="og:site_name" content="龙之叶的博客">
<meta property="og:description" content="Android10.0 人脸解锁流程分析">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://longzhiye.top/images/20231210/20231210001.png">
<meta property="article:published_time" content="2023-12-09T16:00:00.000Z">
<meta property="article:modified_time" content="2024-08-29T02:40:34.915Z">
<meta property="article:author" content="龙之叶">
<meta property="article:tag" content="Android">
<meta property="article:tag" content="SystemUI">
<meta property="article:tag" content="framework">
<meta property="article:tag" content="Launcher">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://longzhiye.top/images/20231210/20231210001.png">

  <meta name="keywords" content=",Android,SystemUI,framework,Launcher">
  <meta name="format-detection" content="telephone=no,email=no">
  <meta name="theme-color" content="#9C27B0">

  <meta name="mobile-web-app-capable" content="yes">
  <meta name="application-name" content="龙之叶的博客">
  <meta name="msapplication-starturl" content="http://longzhiye.top/2023/12/10/2023-12-10/">
  <meta name="msapplication-navbutton-color" content="#9C27B0">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-title" content="龙之叶的博客">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <link rel="apple-touch-icon" href="/images/favicon.png">

  
    <link rel="canonical" href="http://longzhiye.top/2023/12/10/2023-12-10/">
  

  
  

  
  
  

  
<link rel="stylesheet" href="/css/mdui.css">
<link rel="stylesheet" href="/css/style.css">

  
<link rel="stylesheet" href="/custom.css">

<meta name="generator" content="Hexo 5.4.2"></head>

<body class="mdui-appbar-with-toolbar mdui-theme-primary-indigo mdui-theme-accent-pink">
  <script>var a=localStorage.getItem("mdui-theme-layout-dark");if(a){document.getElementsByTagName("body")[0].className+=" mdui-theme-layout-dark"};</script>
  <script>if(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches){document.getElementsByTagName("body")[0].className+=" mdui-theme-layout-dark"};</script>
  <script>var a=localStorage.getItem("mdui-drawer-close");if(!a){document.getElementsByTagName("body")[0].className+=" mdui-drawer-body-left"};</script>
  <header id="header" class="mdui-appbar mdui-appbar-fixed mdui-appbar-scroll-hide mdui-appbar-inset">
  <div class="mdui-toolbar mdui-color-theme">
    <a href="javascript:;" class="mdui-btn mdui-btn-icon" mdui-drawer="{target: '#sidebar', swipe: true}"><i class="mdui-icon material-icons">menu</i></a>
    <a href="/" class="mdui-typo-headline">龙之叶的博客</a>
    <div class="mdui-toolbar-spacer"></div>
    <a href="javascript:;" class="mdui-btn mdui-btn-icon" mdui-dialog="{target: '#search'}" mdui-tooltip="{content: '搜索'}"><i class="mdui-icon material-icons">search</i></a>
	<!--
    <a href="/atom.xml" class="mdui-btn mdui-btn-icon" mdui-tooltip="{content: 'RSS'}"><i class="mdui-icon material-icons">rss_feed</i></a>
	-->
  </div>
</header>
<div class="mdui-dialog" id="search">
  
    <div class="search-form">
      <input type="search" class="search-form-input" placeholder="请输入关键字">
    </div>
    <div class="search-result" data-resource="/search.xml"></div>
  
</div>

  <aside id="sidebar" class="mdui-drawer mdui-drawer-full-height">
  <script>var a=localStorage.getItem("mdui-drawer-close");if(a){document.getElementById("sidebar").className+=" mdui-drawer-close"};</script>
  <div class="mdui-grid-tile">
    <img src="/images/banner.png" style="height: 160px;">
    <img src="/images/avatar.png" class="avatar-animation" style="position: absolute; top: 10%; left: 24px; width: 64px; height: 64px; border: 2px solid #fff; border-radius: 50%;background-color:#fff;">
    <div class="mdui-grid-tile-actions">
      <div class="mdui-grid-tile-text">
        <div class="mdui-grid-tile-title">龙之叶</div>
        <div class="mdui-grid-tile-subtitle"><i class="mdui-icon material-icons">art_track</i>生命不息，折腾不止</div>
      </div>
      
        <div class="mdui-grid-tile-buttons">
          <a href="mailto:longzhiye163@163.com" class="mdui-btn mdui-btn-icon" mdui-tooltip="{content: 'longzhiye163@163.com'}"><i class="mdui-icon material-icons">email</i></a>
        </div>
      
    </div>
  </div>

  <div class="mdui-list" mdui-collapse="{accordion: true}">
    <a href="/" class="mdui-list-item mdui-ripple">
      <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-blue">home</i>
      <div class="mdui-list-item-content">主页</div>
    </a>
    <div class="mdui-collapse-item">
      <script>var a=localStorage.getItem("mdui-collapse-item-0");if(a){document.getElementsByClassName("mdui-collapse-item")[0].className+=" mdui-collapse-item-open"};</script>
      <div class="mdui-collapse-item-header mdui-list-item mdui-ripple">
        <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-deep-orange">archive</i>
        <div class="mdui-list-item-content">归档</div>
        <i class="mdui-collapse-item-arrow mdui-icon material-icons">keyboard_arrow_down</i>
      </div>
      <div class="mdui-collapse-item-body mdui-list mdui-list-dense">
        
        <a class="mdui-ripple sidebar_archives-link" href="/archives/2025/07/">七月 2025<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2025/06/">六月 2025<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2025/03/">三月 2025<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2025/02/">二月 2025<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2025/01/">一月 2025<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/10/">十月 2024<span class="mdui-ripple sidebar_archives-count">7</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/09/">九月 2024<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/08/">八月 2024<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/03/">三月 2024<span class="mdui-ripple sidebar_archives-count">5</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/02/">二月 2024<span class="mdui-ripple sidebar_archives-count">11</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/01/">一月 2024<span class="mdui-ripple sidebar_archives-count">9</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/12/">十二月 2023<span class="mdui-ripple sidebar_archives-count">10</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/11/">十一月 2023<span class="mdui-ripple sidebar_archives-count">8</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/10/">十月 2023<span class="mdui-ripple sidebar_archives-count">8</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/09/">九月 2023<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/08/">八月 2023<span class="mdui-ripple sidebar_archives-count">6</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/06/">六月 2023<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/05/">五月 2023<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/04/">四月 2023<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/03/">三月 2023<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/02/">二月 2023<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2022/09/">九月 2022<span class="mdui-ripple sidebar_archives-count">7</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2022/08/">八月 2022<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2017/04/">四月 2017<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2017/03/">三月 2017<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2017/02/">二月 2017<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2017/01/">一月 2017<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2016/12/">十二月 2016<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2016/11/">十一月 2016<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2016/10/">十月 2016<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2016/08/">八月 2016<span class="mdui-ripple sidebar_archives-count">1</span></a>
        
      </div>
    </div>
    <div class="mdui-collapse-item">
      <script>var a=localStorage.getItem("mdui-collapse-item-1");if(a){document.getElementsByClassName("mdui-collapse-item")[1].className+=" mdui-collapse-item-open"};</script>
      <div class="mdui-collapse-item-header mdui-list-item mdui-ripple">
        <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-green">class</i>
        <div class="mdui-list-item-content">分类</div>
        <i class="mdui-collapse-item-arrow mdui-icon material-icons">keyboard_arrow_down</i>
      </div>
      <div class="mdui-collapse-item-body mdui-list mdui-list-dense">
        
        <a class="mdui-ripple sidebar_archives-link" href="/categories/%E6%8A%80%E6%9C%AF/">技术<span class="mdui-ripple sidebar_archives-count">98</span></a><a class="mdui-ripple sidebar_archives-link" href="/categories/%E7%94%9F%E6%B4%BB/">生活<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/categories/%E8%B5%84%E8%AE%AF/">资讯<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/categories/%E9%80%9A%E7%9F%A5/">通知<span class="mdui-ripple sidebar_archives-count">4</span></a>
        
      </div>
    </div>
    <div class="mdui-collapse-item">
      <script>var a=localStorage.getItem("mdui-collapse-item-2");if(a){document.getElementsByClassName("mdui-collapse-item")[2].className+=" mdui-collapse-item-open"};</script>
      <div class="mdui-collapse-item-header mdui-list-item mdui-ripple">
        <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-brown">bookmark</i>
        <div class="mdui-list-item-content">标签</div>
        <i class="mdui-collapse-item-arrow mdui-icon material-icons">keyboard_arrow_down</i>
      </div>
      <div class="mdui-collapse-item-body mdui-list mdui-list-dense">
        
        <a class="mdui-ripple sidebar_archives-link" href="/tags/ANR/" rel="tag">ANR<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/APP/" rel="tag">APP<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Android/" rel="tag">Android<span class="mdui-ripple sidebar_archives-count">89</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Android12/" rel="tag">Android12<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Android13/" rel="tag">Android13<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Android14/" rel="tag">Android14<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/AndroidStudio/" rel="tag">AndroidStudio<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/AutoDraw/" rel="tag">AutoDraw<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Crash/" rel="tag">Crash<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Foxmail/" rel="tag">Foxmail<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Framework/" rel="tag">Framework<span class="mdui-ripple sidebar_archives-count">20</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/GPS%E8%BD%A8%E8%BF%B9%E5%9B%BE/" rel="tag">GPS轨迹图<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Git/" rel="tag">Git<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/GitHub/" rel="tag">GitHub<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Google/" rel="tag">Google<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Hexo/" rel="tag">Hexo<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Java/" rel="tag">Java<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Kernel/" rel="tag">Kernel<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Launcher/" rel="tag">Launcher<span class="mdui-ripple sidebar_archives-count">17</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Lib/" rel="tag">Lib<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Linux/" rel="tag">Linux<span class="mdui-ripple sidebar_archives-count">18</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Markdown/" rel="tag">Markdown<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Material-Design/" rel="tag">Material Design<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/OS-X/" rel="tag">OS X<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/OTA/" rel="tag">OTA<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/QuickTime/" rel="tag">QuickTime<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/SSH/" rel="tag">SSH<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Settings/" rel="tag">Settings<span class="mdui-ripple sidebar_archives-count">6</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/SystemUI/" rel="tag">SystemUI<span class="mdui-ripple sidebar_archives-count">19</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Ubuntu/" rel="tag">Ubuntu<span class="mdui-ripple sidebar_archives-count">7</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/WPS/" rel="tag">WPS<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Wifi/" rel="tag">Wifi<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/WindTerm/" rel="tag">WindTerm<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Windows/" rel="tag">Windows<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/androidmk/" rel="tag">androidmk<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/blog/" rel="tag">blog<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/build/" rel="tag">build<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/feel/" rel="tag">feel<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/framework/" rel="tag">framework<span class="mdui-ripple sidebar_archives-count">50</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/git/" rel="tag">git<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/inotify/" rel="tag">inotify<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/life/" rel="tag">life<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/ninja/" rel="tag">ninja<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/rsync/" rel="tag">rsync<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/standard/" rel="tag">standard<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/test/" rel="tag">test<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1/" rel="tag">企业微信<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" rel="tag">操作系统<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E6%B5%8B%E8%AF%95/" rel="tag">测试<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E6%BA%90%E7%A0%81/" rel="tag">源码<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E7%94%9F%E6%B4%BB%E6%84%9F%E6%82%9F/" rel="tag">生活感悟<span class="mdui-ripple sidebar_archives-count">1</span></a>
        
      </div>
    </div>
    <a href="/about" class="mdui-list-item mdui-ripple">
      <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-purple">person</i>
      <div class="mdui-list-item-content">关于</div>
    </a>
  </div>

  <div class="mdui-divider"></div>

  <div class="mdui-list" mdui-collapse="{accordion: true}">
    
      <a href="/timeline" class="mdui-list-item mdui-ripple">时间轴</a>
    
    <div class="mdui-collapse-item">
      <script>var a=localStorage.getItem("mdui-collapse-item-3");if(a){document.getElementsByClassName("mdui-collapse-item")[3].className+=" mdui-collapse-item-open"};</script>
      <div class="mdui-collapse-item-header mdui-list-item mdui-ripple">
        <div class="mdui-list-item-content">友情链接</div>
        <i class="mdui-list-item-icon mdui-icon material-icons">link</i>
      </div>
      <div class="mdui-collapse-item-body mdui-list mdui-list-dense">
        
          <a href="http://www.niemingzhao.top" target="_blank" class="mdui-list-item mdui-p-l-2 mdui-text-color-theme-accent mdui-ripple" style="justify-content: center;">聂明照的博客</a>
        
        
      </div>
    </div>
  </div>
</aside>

  <main id="main" class="mdui-m-t-5 fadeIn animated">
  
<link rel="stylesheet" href="//cdn.bootcdn.net/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css">

  <style>#main article .mdui-card-content .center-block{display:block!important;margin-right:auto!important;margin-left:auto!important}</style>
  <style>#main article .mdui-card-content .text-center{text-align:center!important}</style>
  <article class="mdui-card mdui-m-b-5">
    <header class="mdui-card-media">
      <img src="/images/random/material-1.png" style="max-height: 240px;">
      <div class="mdui-card-media-covered">
        <div class="mdui-card-primary">
          <div class="mdui-card-primary-title">Android10.0 人脸解锁流程分析</div>
          <div class="mdui-card-primary-subtitle"><i class="iconfont">&#xe697;</i> 2023-12-10 / <i class="iconfont">&#xe601;</i> 龙之叶 &nbsp;&nbsp; <span id="busuanzi_container_page_pv" style="display: none;"><i class="iconfont">&#xe7fd;</i> <span id="busuanzi_value_page_pv"></span></span></div>
        </div>
      </div>
      <div class="mdui-card-menu">
        
          <button class="mdui-btn mdui-btn-icon mdui-text-color-white" mdui-menu="{target: '#qrcode', align: 'right'}"><i class="mdui-icon material-icons">devices</i></button>
          <ul class="mdui-menu" id="qrcode">
            
              <li class="mdui-menu-item"><a class="mdui-text-center mdui-ripple">发送到手机</a></li>
            
            <li class="mdui-menu-item" disabled>
              
                <img src="//qr.liantu.com/api.php?w=246&m=10&text=http://longzhiye.top/2023/12/10/2023-12-10/">
              
            </li>
          </ul>
        
        
          <button class="mdui-btn mdui-btn-icon mdui-text-color-white" mdui-menu="{target: '#share_menu', align: 'right'}"><i class="mdui-icon material-icons">share</i></button>
          <ul class="mdui-menu" id="share_menu">
            <li class="mdui-menu-item">
              <a href="https://service.weibo.com/share/share.php?appkey=&title=Android10.0 人脸解锁流程分析&url=http://longzhiye.top/2023/12/10/2023-12-10/&pic=http://longzhiye.top/images/favicon.png&searchPic=false&style=simple" target="_blank" class="mdui-ripple">分享到 Weibo</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://twitter.com/intent/tweet?text=Android10.0 人脸解锁流程分析&url=http://longzhiye.top/2023/12/10/2023-12-10/&via=龙之叶" target="_blank" class="mdui-ripple">分享到 Twitter</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://www.facebook.com/sharer/sharer.php?u=http://longzhiye.top/2023/12/10/2023-12-10/" target="_blank" class="mdui-ripple">分享到 Facebook</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://plus.google.com/share?url=http://longzhiye.top/2023/12/10/2023-12-10/" target="_blank" class="mdui-ripple">分享到 Google+</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://www.linkedin.com/shareArticle?mini=true&url=http://longzhiye.top/2023/12/10/2023-12-10/&title=Android10.0 人脸解锁流程分析" target="_blank" class="mdui-ripple">分享到 LinkedIn</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://connect.qq.com/widget/shareqq/index.html?site=龙之叶的博客&title=Android10.0 人脸解锁流程分析&pics=http://longzhiye.top/images/favicon.png&url=http://longzhiye.top/2023/12/10/2023-12-10/" target="_blank" class="mdui-ripple">分享到 QQ</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://telegram.me/share/url?url=http://longzhiye.top/2023/12/10/2023-12-10/&text=Android10.0 人脸解锁流程分析" target="_blank" class="mdui-ripple">分享到 Telegram</a>
            </li>
          </ul>
        
      </div>
    </header>
    <div class="mdui-card-content mdui-typo">
      <h3 id="人脸解锁概述"><a href="#人脸解锁概述" class="headerlink" title="人脸解锁概述"></a>人脸解锁概述</h3><p>人脸解锁即用户通过注视设备的正面方便地解锁手机或平板。Android 10 为支持人脸解锁的设备在人脸认证期间添加了一个新的可以安全处理相机帧、保持隐私与安全的人脸认证栈的支持，也为安全合规地启用集成交易的应用（网上银行或其他服务）提供了一种容易实现的方式。<br>Android 原生的人脸认证栈在 Android 10 是一种新的实现，与 Android P 不一样了。新增 IBiometricsFace.hal ，IBiometricsFaceClientCallback.hal 和 types.hal 这些接口。例如：我这边的源码都是 extends 以上接口，进行了些扩展后再实现的。</p>
<h3 id="底层-Face-HIDL简单认识"><a href="#底层-Face-HIDL简单认识" class="headerlink" title="底层 Face HIDL简单认识"></a>底层 Face HIDL简单认识</h3><p>为了实现 Face HIDL，必须在供应商 (vendor) 指定的库 (library) 里实现 IBiometricsFace.hal 的所有方法。接下来我们就来看看 hardware/interfaces/biometrics/face/1.0 目录下的源代码。<br><strong>hardware/interfaces/biometrics/face/1.0/IBiometricsFace.hal</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> android.hardware.biometrics.face@<span class="number">1.0</span>;</span><br><span class="line"><span class="keyword">import</span> IBiometricsFaceClientCallback;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 用于人脸认证的 HAL 接口</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">IBiometricsFace</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置当前的客户端回调</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;setActiveUser&quot;&#125;)</span></span><br><span class="line">    <span class="meta">@entry</span></span><br><span class="line">    setCallback(IBiometricsFaceClientCallback clientCallback)</span><br><span class="line">        generates (OptionalUint64 result);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置所有随后的 HAL 操作作用于上面的活跃用户</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;authenticate&quot;, &quot;generateChallenge&quot;, &quot;enumerate&quot;, &quot;remove&quot;&#125;)</span></span><br><span class="line">    setActiveUser(int32_t userId, string storePath) generates (Status status);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 生成随机数，用于 token 校验</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;enroll&quot;, &quot;revokeChallenge&quot;, &quot;setFeature&quot;&#125;)</span></span><br><span class="line">    generateChallenge(uint32_t challengeTimeoutSec)</span><br><span class="line">        generates (OptionalUint64 result);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 录入一张用户的人脸</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;cancel&quot;, &quot;enroll&quot;, &quot;revokeChallenge&quot;, &quot;remove&quot;&#125;)</span></span><br><span class="line">    enroll(vec&lt;uint8_t&gt; hat, uint32_t timeoutSec, vec&lt;Feature&gt; disabledFeatures)</span><br><span class="line">        generates (Status status);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 撤销随机数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;authenticate&quot;, &quot;setActiveUser&quot;, &quot;enumerate&quot;, &quot;remove&quot;&#125;)</span></span><br><span class="line">    revokeChallenge() generates (Status status);</span><br><span class="line">    setFeature(Feature feature, bool enabled, vec&lt;uint8_t&gt; hat, uint32_t faceId)</span><br><span class="line">        generates(Status status);</span><br><span class="line">    getFeature(Feature feature, uint32_t faceId) generates (OptionalBool result);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回和当前人脸集关联的标识符 (ID)，认证者 ID</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;authenticate&quot;&#125;)</span></span><br><span class="line">    getAuthenticatorId() generates (OptionalUint64 result);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 取消当前的录入、认证、删除人脸或枚举人脸的操作</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;authenticate&quot;, &quot;enroll&quot;, &quot;enumerate&quot;, &quot;remove&quot;,</span></span><br><span class="line"><span class="meta">        &quot;setActiveUser&quot;&#125;)</span></span><br><span class="line">    cancel() generates (Status status);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 枚举正在使用系统的用户的所有人脸模板</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;remove&quot;, &quot;enroll&quot;, &quot;authenticate&quot;, &quot;setActiveUser&quot;&#125;)</span></span><br><span class="line">    enumerate() generates (Status status);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 删除正在使用系统的用户的一个或所有人脸模板</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;enumerate&quot;, &quot;authenticate&quot;, &quot;cancel&quot;, &quot;getAuthenticatorId&quot;,</span></span><br><span class="line"><span class="meta">        &quot;setActiveUser&quot;&#125;)</span></span><br><span class="line">    remove(uint32_t faceId) generates (Status status);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 认证当前用户是否登录系统的用户</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@callflow(next=&#123;&quot;cancel&quot;, &quot;generateChallenge&quot;, &quot;remove&quot;&#125;)</span></span><br><span class="line">    authenticate(uint64_t operationId) generates (Status status);</span><br><span class="line">    userActivity() generates (Status status);</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 为当前用户重置禁用状态</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    resetLockout(vec&lt;uint8_t&gt; hat) generates (Status status);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p><strong>hardware/interfaces/biometrics/face/1.0/IBiometricsFaceClientCallback.hal</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> android.hardware.biometrics.face@<span class="number">1.0</span>;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 这个回调接口被客户端用来接收人脸 HAL 的（状态）更新</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">IBiometricsFaceClientCallback</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当录入的步骤完成时被回调</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    oneway <span class="title function_">onEnrollResult</span><span class="params">(uint64_t deviceId, uint32_t faceId, int32_t userId,</span></span><br><span class="line"><span class="params">        uint32_t remaining)</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当一张人脸被成功认证时被回调</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    oneway <span class="title function_">onAuthenticated</span><span class="params">(uint64_t deviceId, uint32_t faceId, int32_t userId,</span></span><br><span class="line"><span class="params">        vec&lt;uint8_t&gt; token)</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当底层获得一张人脸时被回调</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">     oneway <span class="title function_">onAcquired</span><span class="params">(uint64_t deviceId, int32_t userId,</span></span><br><span class="line"><span class="params">         FaceAcquiredInfo acquiredInfo, int32_t vendorCode)</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当错误发生时被回调</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    oneway <span class="title function_">onError</span><span class="params">(uint64_t deviceId, int32_t userId, FaceError error,</span></span><br><span class="line"><span class="params">        int32_t vendorCode)</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当人脸模板被删除时被回调</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    oneway <span class="title function_">onRemoved</span><span class="params">(uint64_t deviceId, vec&lt;uint32_t&gt; removed, int32_t userId)</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 枚举所有人脸模板的回调</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    oneway <span class="title function_">onEnumerate</span><span class="params">(uint64_t deviceId, vec&lt;uint32_t&gt; faceIds,</span></span><br><span class="line"><span class="params">        int32_t userId)</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当禁用状态改变时被回调</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    oneway <span class="title function_">onLockoutChanged</span><span class="params">(uint64_t duration)</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>供应商（主要是手机厂商）需要实现上述接口的方法并集成人脸识别算法，完成录入和认证等的底层实现。<br><strong>hardware/interfaces/biometrics/face/1.0/types.hal</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> android.hardware.biometrics.face@<span class="number">1.0</span>;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 在这里 setActiveUser 不会被调用，所有错误消息会返回这个用户 ID</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">UserHandle</span> : int32_t &#123;</span><br><span class="line">    NONE = -<span class="number">1</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 状态码</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Status</span> : uint32_t &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 方法被成功调用</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    OK = <span class="number">0</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 方法调用的参数之一无效</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    ILLEGAL_ARGUMENT = <span class="number">1</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸 HAL 不支持这个操作</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    OPERATION_NOT_SUPPORTED = <span class="number">2</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *  HAL 遭遇内部错误，不能完成请求</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    INTERNAL_ERROR = <span class="number">3</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 没有录入人脸</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    NOT_ENROLLED = <span class="number">4</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Feature</span> : uint32_t &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 要求注视</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    REQUIRE_ATTENTION = <span class="number">1</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 要求录入时姿势多样（有变化） </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    REQUIRE_DIVERSITY = <span class="number">2</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * onError 回调的人脸错误消息</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">FaceError</span> : int32_t &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 不能被解析的硬件错误</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    HW_UNAVAILABLE = <span class="number">1</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 不能处理当前操作</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    UNABLE_TO_PROCESS = <span class="number">2</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 超时</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TIMEOUT = <span class="number">3</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 没有足够的存储空间去完成当前的操作</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    NO_SPACE = <span class="number">4</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 被取消</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    CANCELED = <span class="number">5</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 无法删除</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    UNABLE_TO_REMOVE = <span class="number">6</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 30s 禁用</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    LOCKOUT = <span class="number">7</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 用来开启供应商指定的错误消息</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    VENDOR = <span class="number">8</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 禁用直到使用主身份认证</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    LOCKOUT_PERMANENT = <span class="number">9</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 向客户端反馈获取人脸的消息（质量），以便用户做出相应的改变</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">FaceAcquiredInfo</span> : int32_t &#123;</span><br><span class="line">    GOOD = <span class="number">0</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 无效人脸</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    INSUFFICIENT = <span class="number">1</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸太亮</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TOO_BRIGHT = <span class="number">2</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸太暗</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TOO_DARK = <span class="number">3</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸太近</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TOO_CLOSE = <span class="number">4</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸太远</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TOO_FAR = <span class="number">5</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸太高，只有下半部分</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    FACE_TOO_HIGH = <span class="number">6</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸太低</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    FACE_TOO_LOW = <span class="number">7</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸偏右</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    FACE_TOO_RIGHT = <span class="number">8</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸偏左</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    FACE_TOO_LEFT = <span class="number">9</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 凝视不佳</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    POOR_GAZE = <span class="number">10</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 未检测到人脸</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    NOT_DETECTED = <span class="number">11</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 检测到运动过多</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TOO_MUCH_MOTION = <span class="number">12</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重新校正</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    RECALIBRATE = <span class="number">13</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 和前一帧差异太大</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TOO_DIFFERENT = <span class="number">14</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 和前一帧太相似</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TOO_SIMILAR = <span class="number">15</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 摇射角度太大，直面相机角度为 0</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    PAN_TOO_EXTREME = <span class="number">16</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 倾斜角度太大</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TILT_TOO_EXTREME = <span class="number">17</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 侧倾角幅度太大</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    ROLL_TOO_EXTREME = <span class="number">18</span>,</span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 人脸被遮挡</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    FACE_OBSCURED = <span class="number">19</span>,</span><br><span class="line">    START = <span class="number">20</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 传感器（摄像头）脏了</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    SENSOR_DIRTY = <span class="number">21</span>,</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 用于开启供应商指定的获取人脸的消息</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    VENDOR = <span class="number">22</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 结果</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">struct OptionalUint64 &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回的状态</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Status status;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 只意味着状态是 OK 的</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    uint64_t value;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 结果</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">struct OptionalBool &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回的状态</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Status status;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 只意味着状态是 OK 的</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    bool value;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h3 id="人脸识别调用流程-注册监听、捕获人脸、比对"><a href="#人脸识别调用流程-注册监听、捕获人脸、比对" class="headerlink" title="人脸识别调用流程(注册监听、捕获人脸、比对)"></a>人脸识别调用流程(注册监听、捕获人脸、比对)</h3><p>人脸解锁的入口在Keyguard中，但息屏的处理是从PowerManager开始，最终到锁屏的核心类KeyguardViewMediator，息屏处理的大致流程如下：<br><img src="/images/20231210/20231210001.png"></p>
<p>前面几步就跳过，直接从PhoneWindowManager开始分析。灭屏之后会调用PhoneWindowManager的startedGoingToSleep方法：<br><strong>frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Called on the PowerManager&#x27;s Notifier thread.</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">startedGoingToSleep</span><span class="params">(<span class="type">int</span> why)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (DEBUG_WAKEUP) &#123;</span><br><span class="line">        Slog.i(TAG, <span class="string">&quot;Started going to sleep... (why=&quot;</span></span><br><span class="line">                + WindowManagerPolicyConstants.offReasonToString(why) + <span class="string">&quot;)&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    mGoingToSleep = <span class="literal">true</span>;</span><br><span class="line">    mRequestedOrGoingToSleep = <span class="literal">true</span>;</span><br><span class="line">    <span class="keyword">if</span> (mKeyguardDelegate != <span class="literal">null</span>) &#123;</span><br><span class="line">        mKeyguardDelegate.onStartedGoingToSleep(why);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在该方法中又调用了KeyguardServiceDelegate类的onStartedGoingToSleep方法。<br>KeyguardServiceDelegate#onStartedGoingToSleep →KeyguardServiceWrapper#onStartedGoingToSleep → KeyguardService#onStartedGoingToSleep  → KeyguardViewMediator#onStartedGoingToSleep，最终会调用到KeyguardViewMediator锁屏核心类。<br><strong>frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onStartedGoingToSleep</span><span class="params">(<span class="type">int</span> why)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (DEBUG) Log.d(TAG, <span class="string">&quot;onStartedGoingToSleep(&quot;</span> + why + <span class="string">&quot;)&quot;</span>);</span><br><span class="line">    <span class="keyword">synchronized</span> (<span class="built_in">this</span>) &#123;</span><br><span class="line">        mDeviceInteractive = <span class="literal">false</span>;</span><br><span class="line">        mGoingToSleep = <span class="literal">true</span>;</span><br><span class="line">        <span class="comment">// 这位置的代码作用具体不知，但放在前面可以解决息屏后又立马使用指纹解锁时：出现1.2s内没反应的问题。</span></span><br><span class="line">        mUpdateMonitor.dispatchKeyguardGoingAway(<span class="literal">false</span>);</span><br><span class="line">        <span class="comment">// Lock immediately based on setting if secure (user has a pin/pattern/password).</span></span><br><span class="line">        <span class="comment">// This also &quot;locks&quot; the device when not secure to provide easy access to the</span></span><br><span class="line">        <span class="comment">// camera while preventing unwanted input.</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">currentUser</span> <span class="operator">=</span> KeyguardUpdateMonitor.getCurrentUser();</span><br><span class="line">        <span class="keyword">final</span> <span class="type">boolean</span> <span class="variable">lockImmediately</span> <span class="operator">=</span></span><br><span class="line">                mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser)</span><br><span class="line">                        || !mLockPatternUtils.isSecure(currentUser);</span><br><span class="line">        <span class="type">long</span> <span class="variable">timeout</span> <span class="operator">=</span> getLockTimeout(KeyguardUpdateMonitor.getCurrentUser());</span><br><span class="line">        mLockLater = <span class="literal">false</span>;</span><br><span class="line">        <span class="comment">// 省略部分代码......</span></span><br><span class="line">        <span class="comment">//判断是否需要播放锁屏音</span></span><br><span class="line">        <span class="keyword">if</span> (mPendingLock) &#123;</span><br><span class="line">            playSounds(<span class="literal">true</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 使得KeyguardUpdateMonitor可以监听到GoingToSleep</span></span><br><span class="line">    <span class="comment">// KeyguardUpdateMonitor 是Keyguard更新监视器</span></span><br><span class="line">    mUpdateMonitor.dispatchStartedGoingToSleep(why);</span><br><span class="line">    <span class="comment">//通知开始息屏</span></span><br><span class="line">    notifyStartedGoingToSleep();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里主要分析的是屏幕自己息屏，则重点关注mUpdateMonitor.dispatchStartedGoingToSleep(why)。<br><strong>frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 等待屏幕超时息屏，handler会发送 MSG_STARTED_GOING_TO_SLEEP</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">dispatchStartedGoingToSleep</span><span class="params">(<span class="type">int</span> why)</span> &#123;</span><br><span class="line">    mHandler.sendMessage(mHandler.obtainMessage(MSG_STARTED_GOING_TO_SLEEP, why, <span class="number">0</span>));</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 注意：如果说按电源键息屏，handler会发送 MSG_STARTED_WAKING_UP</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">dispatchStartedWakingUp</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">synchronized</span> (<span class="built_in">this</span>) &#123;</span><br><span class="line">        mDeviceInteractive = <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    mHandler.sendEmptyMessage(MSG_STARTED_WAKING_UP);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>屏幕超时息屏堆栈：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState: java.lang.Throwable</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2128)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.updateBiometricListeningState(KeyguardUpdateMonitor.java:2053)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.setKeyguardGoingAway(KeyguardUpdateMonitor.java:575)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.handleKeyguardGoingAway(KeyguardUpdateMonitor.java:1727)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.access$5000(KeyguardUpdateMonitor.java:143)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor$16.handleMessage(KeyguardUpdateMonitor.java:1872)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.os.Handler.dispatchMessage(Handler.java:106)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.os.Looper.loop(Looper.java:223)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.app.ActivityThread.main(ActivityThread.java:7945)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at java.lang.reflect.Method.invoke(Native Method)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)</span><br><span class="line">12-10 09:43:41.437  1468  1468 V KeyguardUpdateMonitor:         at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2129)</span><br></pre></td></tr></table></figure>
<p>电源键息屏堆栈：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState: java.lang.Throwable</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2128)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.updateBiometricListeningState(KeyguardUpdateMonitor.java:2053)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.setKeyguardGoingAway(KeyguardUpdateMonitor.java:575)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.handleKeyguardGoingAway(KeyguardUpdateMonitor.java:1727)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.access$5000(KeyguardUpdateMonitor.java:143)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor$16.handleMessage(KeyguardUpdateMonitor.java:1872)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.os.Handler.dispatchMessage(Handler.java:106)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.os.Looper.loop(Looper.java:223)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.app.ActivityThread.main(ActivityThread.java:7945)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at java.lang.reflect.Method.invoke(Native Method)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)</span><br><span class="line">12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)</span><br><span class="line">12-10 09:43:41.437  1468  1468 V KeyguardUpdateMonitor:         at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2129)</span><br></pre></td></tr></table></figure>
<p>这里通过handler发送消息让：handleStartedGoingToSleep处理<br><strong>frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">handleStartedGoingToSleep</span><span class="params">(<span class="type">int</span> arg1)</span> &#123;</span><br><span class="line">    checkIsHandlerThread();</span><br><span class="line">    mLockIconPressed = <span class="literal">false</span>;</span><br><span class="line">    clearBiometricRecognized();</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; mCallbacks.size(); i++) &#123;</span><br><span class="line">        <span class="type">KeyguardUpdateMonitorCallback</span> <span class="variable">cb</span> <span class="operator">=</span> mCallbacks.get(i).get();</span><br><span class="line">        <span class="keyword">if</span> (cb != <span class="literal">null</span>) &#123;</span><br><span class="line">            cb.onStartedGoingToSleep(arg1);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    mGoingToSleep = <span class="literal">true</span>;</span><br><span class="line">    <span class="comment">// 更新生物识别（指纹、人脸）</span></span><br><span class="line">    updateBiometricListeningState();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">updateBiometricListeningState</span><span class="params">()</span> &#123;</span><br><span class="line">    updateFingerprintListeningState();</span><br><span class="line">    updateFaceListeningState();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>updateFaceListeningState()，更新人脸状态。<br><strong>frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">updateFaceListeningState</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// 如果此消息存在，我们不应再次进行身份验证</span></span><br><span class="line">    <span class="keyword">if</span> (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    mHandler.removeCallbacks(mRetryFaceAuthentication);</span><br><span class="line">    <span class="type">boolean</span> <span class="variable">shouldListenForFace</span> <span class="operator">=</span> shouldListenForFace();</span><br><span class="line">    <span class="keyword">if</span> (mFaceRunningState == BIOMETRIC_STATE_RUNNING &amp;&amp; !shouldListenForFace) &#123;</span><br><span class="line">        stopListeningForFace();</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (mFaceRunningState != BIOMETRIC_STATE_RUNNING &amp;&amp;  shouldListenForFace) &#123;</span><br><span class="line">        <span class="comment">// 在这里开始监听人脸</span></span><br><span class="line">        <span class="comment">/*重点关注*/</span></span><br><span class="line">        startListeningForFace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>startListeningForFace()<br><strong>frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">startListeningForFace</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (mFaceRunningState == BIOMETRIC_STATE_CANCELLING) &#123;</span><br><span class="line">        setFaceRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (DEBUG) Log.v(TAG, <span class="string">&quot;startListeningForFace()&quot;</span>);</span><br><span class="line">    <span class="type">int</span> <span class="variable">userId</span> <span class="operator">=</span> getCurrentUser();</span><br><span class="line">    <span class="keyword">if</span> (isUnlockWithFacePossible(userId)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (mFaceCancelSignal != <span class="literal">null</span>) &#123;</span><br><span class="line">            mFaceCancelSignal.cancel();</span><br><span class="line">        &#125;</span><br><span class="line">        mFaceCancelSignal = <span class="keyword">new</span> <span class="title class_">CancellationSignal</span>();</span><br><span class="line">        <span class="comment">/*重点关注*/</span></span><br><span class="line">        mFaceManager.authenticate(<span class="literal">null</span>, mFaceCancelSignal, <span class="number">0</span>,</span><br><span class="line">                mFaceAuthenticationCallback, <span class="literal">null</span>, userId);</span><br><span class="line">        setFaceRunningState(BIOMETRIC_STATE_RUNNING);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>FaceManager#authenticate()<br><strong>frameworks/base/core/java/android/hardware/face/FaceManager.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">authenticate</span><span class="params">(<span class="meta">@Nullable</span> CryptoObject crypto, <span class="meta">@Nullable</span> CancellationSignal cancel,</span></span><br><span class="line"><span class="params">        <span class="type">int</span> flags, <span class="meta">@NonNull</span> AuthenticationCallback callback, <span class="meta">@Nullable</span> Handler handler,</span></span><br><span class="line"><span class="params">        <span class="type">int</span> userId)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (callback == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Must supply an authentication callback&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(mPendingFaceAuth != <span class="literal">null</span>) &#123;</span><br><span class="line">        Log.w(TAG, <span class="string">&quot;authentication too frequent&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(mAuthenticationCallback != <span class="literal">null</span>) &#123;</span><br><span class="line">        mPendingFaceAuth = <span class="keyword">new</span> <span class="title class_">PendingFaceAuth</span>(crypto, cancel, flags, callback, handler, userId);</span><br><span class="line">        Log.w(TAG, <span class="string">&quot;pengding face auth&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">/*重点关注*/</span></span><br><span class="line">        authenticateInternel(crypto, cancel, flags, callback, handler, userId);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">void</span> <span class="title function_">authenticateInternel</span><span class="params">(CryptoObject crypto, CancellationSignal cancel,</span></span><br><span class="line"><span class="params">        <span class="type">int</span> flags, AuthenticationCallback callback, Handler handler, <span class="type">int</span> userId)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (cancel != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (cancel.isCanceled()) &#123;</span><br><span class="line">            Log.w(TAG, <span class="string">&quot;authentication already canceled&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            cancel.setOnCancelListener(<span class="keyword">new</span> <span class="title class_">OnAuthenticationCancelListener</span>(crypto));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//mSurface = null;</span></span><br><span class="line">    <span class="comment">//onFaceidStarted();</span></span><br><span class="line">    <span class="keyword">if</span> (mService != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            useHandler(handler);</span><br><span class="line">            mAuthenticationCallback = callback;</span><br><span class="line">            mCryptoObject = crypto;</span><br><span class="line">            <span class="type">long</span> <span class="variable">sessionId</span> <span class="operator">=</span> crypto != <span class="literal">null</span> ? crypto.getOpId() : <span class="number">0</span>;</span><br><span class="line">            Trace.beginSection(<span class="string">&quot;FaceManager#authenticate&quot;</span>);</span><br><span class="line">            <span class="comment">/*重点关注*/</span>    </span><br><span class="line">            <span class="comment">// 进行人脸认证  </span></span><br><span class="line">            mService.authenticate(mToken, sessionId, userId, mServiceReceiver,</span><br><span class="line">                    flags, mContext.getOpPackageName());</span><br><span class="line">            <span class="comment">/* UNISOC: Modify for bug1374210 &#123;@ */</span></span><br><span class="line">            <span class="keyword">if</span> (callback != <span class="literal">null</span>) &#123;</span><br><span class="line">                callback.onAuthenticationStarted();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">/* @&#125; */</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (RemoteException e) &#123;</span><br><span class="line">             <span class="comment">// 省略部分代码......</span></span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            Trace.endSection();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>FaceService#authenticate()<br><strong>frameworks/base/services/core/java/com/android/server/biometrics/face/FaceService.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span> <span class="comment">// Binder call</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">authenticate</span><span class="params">(<span class="keyword">final</span> IBinder token, <span class="keyword">final</span> <span class="type">long</span> opId, <span class="type">int</span> userId,</span></span><br><span class="line"><span class="params">        <span class="keyword">final</span> IFaceServiceReceiver receiver, <span class="keyword">final</span> <span class="type">int</span> flags,</span></span><br><span class="line"><span class="params">        <span class="keyword">final</span> String opPackageName)</span> &#123;</span><br><span class="line">    checkPermission(USE_BIOMETRIC_INTERNAL);</span><br><span class="line">    updateActiveGroup(userId, opPackageName);</span><br><span class="line">    <span class="keyword">final</span> <span class="type">boolean</span> <span class="variable">restricted</span> <span class="operator">=</span> isRestricted();</span><br><span class="line">    <span class="keyword">final</span> <span class="type">AuthenticationClientImpl</span> <span class="variable">client</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FaceAuthClient</span>(getContext(),</span><br><span class="line">            mDaemonWrapper, mHalDeviceId, token, <span class="keyword">new</span> <span class="title class_">ServiceListenerImpl</span>(receiver),</span><br><span class="line">            mCurrentUserId, <span class="number">0</span> <span class="comment">/* groupId */</span>, opId, restricted, opPackageName,</span><br><span class="line">            <span class="number">0</span> <span class="comment">/* cookie */</span>, <span class="literal">false</span> <span class="comment">/* requireConfirmation */</span>);</span><br><span class="line">     <span class="comment">/*重点关注*/</span></span><br><span class="line">    authenticateInternal(client, opId, opPackageName);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>BiometricServiceBase#authenticateInternal()</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">authenticateInternal</span><span class="params">(AuthenticationClientImpl client, <span class="type">long</span> opId,</span></span><br><span class="line"><span class="params">            String opPackageName)</span> &#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="type">int</span> <span class="variable">callingUid</span> <span class="operator">=</span> Binder.getCallingUid();</span><br><span class="line">        <span class="keyword">final</span> <span class="type">int</span> <span class="variable">callingPid</span> <span class="operator">=</span> Binder.getCallingPid();</span><br><span class="line">        <span class="keyword">final</span> <span class="type">int</span> <span class="variable">callingUserId</span> <span class="operator">=</span> UserHandle.getCallingUserId();</span><br><span class="line">        authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">authenticateInternal</span><span class="params">(AuthenticationClientImpl client, <span class="type">long</span> opId,</span></span><br><span class="line"><span class="params">            String opPackageName, <span class="type">int</span> callingUid, <span class="type">int</span> callingPid, <span class="type">int</span> callingUserId)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!canUseBiometric(opPackageName, <span class="literal">true</span> <span class="comment">/* foregroundOnly */</span>, callingUid, callingPid,</span><br><span class="line">                callingUserId)) &#123;</span><br><span class="line">            <span class="keyword">if</span> (DEBUG) Slog.v(getTag(), <span class="string">&quot;authenticate(): reject &quot;</span> + opPackageName);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        mHandler.post(() -&gt; &#123;</span><br><span class="line">            mMetricsLogger.histogram(getConstants().tagAuthToken(), opId != <span class="number">0L</span> ? <span class="number">1</span> : <span class="number">0</span>);</span><br><span class="line">            <span class="comment">// Get performance stats object for this user.</span></span><br><span class="line">            HashMap&lt;Integer, PerformanceStats&gt; pmap</span><br><span class="line">                    = (opId == <span class="number">0</span>) ? mPerformanceMap : mCryptoPerformanceMap;</span><br><span class="line">            <span class="type">PerformanceStats</span> <span class="variable">stats</span> <span class="operator">=</span> pmap.get(mCurrentUserId);</span><br><span class="line">            <span class="keyword">if</span> (stats == <span class="literal">null</span>) &#123;</span><br><span class="line">                stats = <span class="keyword">new</span> <span class="title class_">PerformanceStats</span>();</span><br><span class="line">                pmap.put(mCurrentUserId, stats);</span><br><span class="line">            &#125;</span><br><span class="line">            mPerformanceStats = stats;</span><br><span class="line">            mIsCrypto = (opId != <span class="number">0</span>);</span><br><span class="line">            <span class="comment">/*重点关注*/</span></span><br><span class="line">            startAuthentication(client, opPackageName);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">startAuthentication</span><span class="params">(AuthenticationClientImpl client, String opPackageName)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (DEBUG) Slog.v(getTag(), <span class="string">&quot;startAuthentication(&quot;</span> + opPackageName + <span class="string">&quot;)&quot;</span>);</span><br><span class="line">        <span class="type">int</span> <span class="variable">lockoutMode</span> <span class="operator">=</span> getLockoutMode();</span><br><span class="line">        <span class="comment">// getLockoutMode() 判断是否锁定，会返回一个 int 值</span></span><br><span class="line">        <span class="keyword">if</span> (lockoutMode != AuthenticationClient.LOCKOUT_NONE) &#123;</span><br><span class="line">            Slog.v(getTag(), <span class="string">&quot;In lockout mode(&quot;</span> + lockoutMode + <span class="string">&quot;) ; disallowing authentication&quot;</span>);</span><br><span class="line">            <span class="type">int</span> <span class="variable">errorCode</span> <span class="operator">=</span> lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?</span><br><span class="line">                    BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :</span><br><span class="line">                    BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;</span><br><span class="line">            <span class="keyword">if</span> (!client.onError(getHalDeviceId(), errorCode, <span class="number">0</span> <span class="comment">/* vendorCode */</span>)) &#123;</span><br><span class="line">                Slog.w(getTag(), <span class="string">&quot;Cannot send permanent lockout message to client&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">/*重点关注*/</span></span><br><span class="line">        startClient(client, <span class="literal">true</span> <span class="comment">/* initiatedByClient */</span>);</span><br><span class="line">        <span class="comment">//这里将AuthenticationClient传递进去</span></span><br><span class="line">    &#125;    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">startClient</span><span class="params">(ClientMonitor newClient, <span class="type">boolean</span> initiatedByClient)</span> &#123;</span><br><span class="line">        <span class="type">ClientMonitor</span> <span class="variable">currentClient</span> <span class="operator">=</span> mCurrentClient;</span><br><span class="line">        <span class="keyword">if</span> (currentClient != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (DEBUG) Slog.v(getTag(), <span class="string">&quot;request stop current client &quot;</span> +</span><br><span class="line">                    currentClient.getOwnerString());</span><br><span class="line">            <span class="keyword">if</span> (currentClient <span class="keyword">instanceof</span> InternalEnumerateClient</span><br><span class="line">                    || currentClient <span class="keyword">instanceof</span> InternalRemovalClient) &#123;</span><br><span class="line">                 <span class="comment">// 省略部分代码......</span></span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                currentClient.stop(initiatedByClient);</span><br><span class="line">                mHandler.removeCallbacks(mResetClientState);</span><br><span class="line">                mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);</span><br><span class="line">            &#125;</span><br><span class="line">            mPendingClient = newClient;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (newClient != <span class="literal">null</span>) &#123;</span><br><span class="line">             <span class="comment">// 省略部分代码......</span></span><br><span class="line">            <span class="comment">// We are not a BiometricPrompt client, start the client immediately</span></span><br><span class="line">            mCurrentClient = newClient;</span><br><span class="line">            <span class="comment">/*重点关注*/</span></span><br><span class="line">            startCurrentClient(mCurrentClient.getCookie());</span><br><span class="line">            <span class="comment">//这里继续将AuthenticationClient传递进去</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">startCurrentClient</span><span class="params">(<span class="type">int</span> cookie)</span> &#123;</span><br><span class="line">    </span><br><span class="line">         <span class="comment">// 省略部分代码......</span></span><br><span class="line">         <span class="comment">/*重点关注*/</span></span><br><span class="line">         <span class="comment">//这里调用的是AuthenticationClient的start方法</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">status</span> <span class="operator">=</span> mCurrentClient.start();</span><br><span class="line">        <span class="keyword">if</span> (status == <span class="number">0</span>) &#123;</span><br><span class="line">            notifyClientActiveCallbacks(<span class="literal">true</span>);</span><br><span class="line">        &#125;</span><br><span class="line">      <span class="comment">// ... ...</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>mCurrentClient是ClientMonitor的对象，而AuthenticationClient继承了ClientMonitor类；<br>AuthenticationClient#start()<br><strong>frameworks/base/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 开始验证</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">start</span><span class="params">()</span> &#123;</span><br><span class="line">        mStarted = <span class="literal">true</span>;</span><br><span class="line">        onStart();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">/*重点关注*/</span></span><br><span class="line">            <span class="comment">// 获取 DaemonWrappe 对象开始鉴权，这里如果鉴权完成会回调注册的 ClientMonito r的 onAuthenticated 接口</span></span><br><span class="line">            <span class="comment">//到这一步 DaemonWrappe 对象 进入等待捕获人脸信息，摄像头会给到DaemonWrappe对象人脸信息。</span></span><br><span class="line">            <span class="comment">// 这里对调用到 DaemonWrapper 在 FaceService 里有实现，在那里会直接调用到 HAL 层</span></span><br><span class="line">            <span class="keyword">final</span> <span class="type">int</span> <span class="variable">result</span> <span class="operator">=</span> getDaemonWrapper().authenticate(mOpId, getGroupId());</span><br><span class="line">            <span class="keyword">if</span> (result != <span class="number">0</span>) &#123;</span><br><span class="line">                Slog.w(getLogTag(), <span class="string">&quot;startAuthentication failed, result=&quot;</span> + result);</span><br><span class="line">                mMetricsLogger.histogram(mConstants.tagAuthStartError(), result);</span><br><span class="line">                onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,</span><br><span class="line">                        <span class="number">0</span> <span class="comment">/* vendorCode */</span>);</span><br><span class="line">                <span class="keyword">return</span> result;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (DEBUG) Slog.w(getLogTag(), <span class="string">&quot;client &quot;</span> + getOwnerString() + <span class="string">&quot; is authenticating...&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (RemoteException e) &#123;</span><br><span class="line">            Slog.e(getLogTag(), <span class="string">&quot;startAuthentication failed&quot;</span>, e);</span><br><span class="line">            <span class="keyword">return</span> ERROR_ESRCH;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>; <span class="comment">// success</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>start方法会调用faced，调用底层的人脸库，底层库返回结果后会调用onAuthenticated来反馈结果给receiver，在往上层反馈。<br>补充：IExtBiometricsFace.hal 这个接口在 ExtBiometricsFace.cpp中实现。<br><strong>frameworks/base/services/core/java/com/android/server/biometrics/face/FaceService.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onStart</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="built_in">super</span>.onStart();</span><br><span class="line">    <span class="comment">// 在初始化后会建立和HAL层的通信，即连接到 FaceService，</span></span><br><span class="line">    <span class="comment">//并通过getFaceDaemon()拿到用于通信的 IExtBiometricsFace对象（binder）</span></span><br><span class="line">    publishBinderService(Context.FACE_SERVICE, <span class="keyword">new</span> <span class="title class_">FaceServiceWrapper</span>());</span><br><span class="line"> </span><br><span class="line">    SystemServerInitThreadPool.submit(() -&gt; mHandler.post(<span class="built_in">this</span>::getFaceDaemon),</span><br><span class="line">            TAG + <span class="string">&quot;.onStart&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="屏幕解锁（结果回调、移除锁）"><a href="#屏幕解锁（结果回调、移除锁）" class="headerlink" title="屏幕解锁（结果回调、移除锁）"></a>屏幕解锁（结果回调、移除锁）</h3><p>底层库回调onAuthenticated堆栈:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  : longzhiye：FaceService.java ServiceListenerImpl onAuthenticationSucceeded()</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  : java.lang.Throwable</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.FaceService$ServiceListenerImpl.onAuthenticationSucceeded(FaceService.java:918)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.AuthenticationClient.onAuthenticated(AuthenticationClient.java:235)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.FaceService$FaceAuthClient.onAuthenticated(FaceService.java:297)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.BiometricServiceBase.handleAuthenticated(BiometricServiceBase.java:729)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.FaceService.access$11801(FaceService.java:110)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.FaceService$1.lambda$onAuthenticated$2$FaceService$1(FaceService.java:1040)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.-$$Lambda$FaceService$1$GcU4ZG1fdDLhKvSxuMwfPargEnI.run(Unknown Source:8)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at android.os.Handler.handleCallback(Handler.java:938)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at android.os.Handler.dispatchMessage(Handler.java:99)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at android.os.Looper.loop(Looper.java:223)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.SystemServer.run(SystemServer.java:647)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.SystemServer.main(SystemServer.java:431)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at java.lang.reflect.Method.invoke(Native Method)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)</span><br><span class="line">12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:925)</span><br></pre></td></tr></table></figure>
<p>根据前面的讲的 底层 Face HIDL 可以知道 IExtBiometricsFaceClientCallback 是回调人脸识别结果的。onAuthenticated()是当一张人脸被成功认证时被回调。<br><strong>frameworks/base/services/core/java/com/android/server/biometrics/face/FaceService.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Receives callbacks from the HAL.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="type">IExtBiometricsFaceClientCallback</span> <span class="variable">mDaemonCallback</span> <span class="operator">=</span></span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">IExtBiometricsFaceClientCallback</span>.Stub() &#123;</span><br><span class="line">   </span><br><span class="line">     <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticated</span><span class="params">(<span class="keyword">final</span> <span class="type">long</span> deviceId, <span class="keyword">final</span> <span class="type">int</span> faceId, <span class="keyword">final</span> <span class="type">int</span> userId,</span></span><br><span class="line"><span class="params">            ArrayList&lt;Byte&gt; token)</span> &#123;</span><br><span class="line">        mHandler.post(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="type">Face</span> <span class="variable">face</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Face</span>(<span class="string">&quot;&quot;</span>, faceId, deviceId);</span><br><span class="line">            <span class="keyword">final</span> <span class="type">boolean</span> <span class="variable">authenticated</span> <span class="operator">=</span> faceId != <span class="number">0</span>;</span><br><span class="line">            <span class="comment">/*重点在这里*/</span></span><br><span class="line">            FaceService.<span class="built_in">super</span>.handleAuthenticated(authenticated, face, token);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">     <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>通过上面 FaceService.super.handleAuthenticated(authenticated, face, token) 的调用。将会调用到：<br>BiometricServiceBase#handleAuthenticated()</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// BiometricServiceBase.java</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">handleAuthenticated</span><span class="params">(<span class="type">boolean</span> authenticated,</span></span><br><span class="line"><span class="params">            BiometricAuthenticator.Identifier identifier, ArrayList&lt;Byte&gt; token)</span> &#123;</span><br><span class="line">        Log.d(<span class="string">&quot;longzhiye&quot;</span>,<span class="string">&quot;longzhiye：AuthenticationClient.java ----------------2 &quot;</span>);</span><br><span class="line">        <span class="type">ClientMonitor</span> <span class="variable">client</span> <span class="operator">=</span> mCurrentClient;</span><br><span class="line">        <span class="comment">// 重点在后半句判断，通过前面的分析可以知道 client 其实是 FaceAuthClient 的对象</span></span><br><span class="line">        <span class="keyword">if</span> (client != <span class="literal">null</span> &amp;&amp; client.onAuthenticated(identifier, authenticated, token)) &#123;</span><br><span class="line">            removeClient(client);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (authenticated) &#123;</span><br><span class="line">            mPerformanceStats.accept++;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            mPerformanceStats.reject++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>通过前面的分析可以知道 client 其实是 FaceAuthClient 的对象，在FaceService.java 的内部类FaceServiceWrapper的authenticate()方法进行实例化传过去的。反正最终将会回调到FaceService.java 的内部类FaceAuthClient的onAuthenticated()方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">onAuthenticated</span><span class="params">(BiometricAuthenticator.Identifier identifier,</span></span><br><span class="line"><span class="params">        <span class="type">boolean</span> authenticated, ArrayList&lt;Byte&gt; token)</span> &#123;</span><br><span class="line">    Log.d(<span class="string">&quot;longzhiye&quot;</span>,<span class="string">&quot;longzhiye onAuthenticated &quot;</span>,<span class="keyword">new</span> <span class="title class_">Throwable</span>());</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 重点关注super</span></span><br><span class="line">    <span class="keyword">final</span> <span class="type">boolean</span> <span class="variable">result</span> <span class="operator">=</span> <span class="built_in">super</span>.onAuthenticated(identifier, authenticated, token);</span><br><span class="line"></span><br><span class="line">    mUsageStats.addEvent(<span class="keyword">new</span> <span class="title class_">AuthenticationEvent</span>(</span><br><span class="line">            getStartTimeMs(),</span><br><span class="line">            System.currentTimeMillis() - getStartTimeMs() <span class="comment">/* latency */</span>,</span><br><span class="line">            authenticated,</span><br><span class="line">            <span class="number">0</span> <span class="comment">/* error */</span>,</span><br><span class="line">            <span class="number">0</span> <span class="comment">/* vendorError */</span>,</span><br><span class="line">            getTargetUserId()));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// For face, the authentication lifecycle ends either when</span></span><br><span class="line">    <span class="comment">// 1) Authenticated == true</span></span><br><span class="line">    <span class="comment">// 2) Error occurred</span></span><br><span class="line">    <span class="comment">// 3) Authenticated == false</span></span><br><span class="line">    <span class="comment">// Fingerprint currently does not end when the third condition is met which is a bug,</span></span><br><span class="line">    <span class="comment">// but let&#x27;s leave it as-is for now.</span></span><br><span class="line">    <span class="keyword">return</span> result || !authenticated;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里的super将会调到父类AuthenticationClient中的onAuthenticated()。<br>AuthenticationClient#onAuthenticated()<br><strong>frameworks/base/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">onAuthenticated</span><span class="params">(BiometricAuthenticator.Identifier identifier,</span></span><br><span class="line"><span class="params">        <span class="type">boolean</span> authenticated, ArrayList&lt;Byte&gt; token)</span> &#123;</span><br><span class="line">    <span class="built_in">super</span>.logOnAuthenticated(getContext(), authenticated, mRequireConfirmation,</span><br><span class="line">            getTargetUserId(), isBiometricPrompt());</span><br><span class="line">      <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (DEBUG) Slog.v(getLogTag(), <span class="string">&quot;onAuthenticated(&quot;</span> + authenticated + <span class="string">&quot;)&quot;</span></span><br><span class="line">                + <span class="string">&quot;, ID:&quot;</span> + identifier.getBiometricId()</span><br><span class="line">                + <span class="string">&quot;, Owner: &quot;</span> + getOwnerString()</span><br><span class="line">                + <span class="string">&quot;, isBP: &quot;</span> + isBiometricPrompt()</span><br><span class="line">                + <span class="string">&quot;, listener: &quot;</span> + listener</span><br><span class="line">                + <span class="string">&quot;, requireConfirmation: &quot;</span> + mRequireConfirmation</span><br><span class="line">                + <span class="string">&quot;, user: &quot;</span> + getTargetUserId());</span><br><span class="line">        <span class="keyword">if</span> (authenticated) &#123; </span><br><span class="line">          <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="comment">// Explicitly have if/else here to make it super obvious in case the code is</span></span><br><span class="line">                    <span class="comment">// touched in the future.</span></span><br><span class="line">                    <span class="keyword">if</span> (!getIsRestricted()) &#123;</span><br><span class="line">                        <span class="comment">/*重点关注*/</span> </span><br><span class="line">                        <span class="comment">// getIsRestricted() 获取有没有权限登录，说白了就是验证是否成功</span></span><br><span class="line">                        listener.onAuthenticationSucceeded(</span><br><span class="line">                                getHalDeviceId(), identifier, getTargetUserId());</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        listener.onAuthenticationSucceeded(</span><br><span class="line">                                getHalDeviceId(), <span class="literal">null</span>, getTargetUserId());</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (RemoteException e) &#123;</span><br><span class="line">                    Slog.e(getLogTag(), <span class="string">&quot;Remote exception&quot;</span>, e);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// Client not listening</span></span><br><span class="line">                Slog.w(getLogTag(), <span class="string">&quot;Client not listening&quot;</span>);</span><br><span class="line">                result = <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">         <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (RemoteException e) &#123;</span><br><span class="line">        Slog.e(getLogTag(), <span class="string">&quot;Remote exception&quot;</span>, e);</span><br><span class="line">        result = <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里的 listener 其实是 BiometricServiceBase.ServiceListener 接口的回调，BiometricServiceBase的内部类BiometricServiceListener也实现了该接口，但是没有实现onAuthenticationSucceeded() 方法，而该ServiceListener 接口在FaceService中的内部类ServiceListenerImpl 也有实现，并且实现了onAuthenticationSucceeded() 方法。所以将会回调到FaceService内部类的 ServiceListenerImpl#onAuthenticationSucceeded()。<br>ServiceListenerImpl#onAuthenticationSucceeded()</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 从 ClientMonitor 实现接收回调。结果被转发到 FaceManager</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">class</span> <span class="title class_">ServiceListenerImpl</span> <span class="keyword">implements</span> <span class="title class_">ServiceListener</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> IFaceServiceReceiver mFaceServiceReceiver;</span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">ServiceListenerImpl</span><span class="params">(IFaceServiceReceiver receiver)</span> &#123;</span><br><span class="line">            mFaceServiceReceiver = receiver;</span><br><span class="line">        &#125;</span><br><span class="line">         <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticationSucceeded</span><span class="params">(<span class="type">long</span> deviceId,</span></span><br><span class="line"><span class="params">                BiometricAuthenticator.Identifier biometric, <span class="type">int</span> userId)</span></span><br><span class="line">                <span class="keyword">throws</span> RemoteException &#123;</span><br><span class="line">            <span class="keyword">if</span> (mFaceServiceReceiver != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (biometric == <span class="literal">null</span> || biometric <span class="keyword">instanceof</span> Face) &#123;</span><br><span class="line">                    <span class="comment">// 重点关注这里</span></span><br><span class="line">                    mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face) biometric,</span><br><span class="line">                            userId, isStrongBiometric());</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    Slog.e(TAG, <span class="string">&quot;onAuthenticationSucceeded received non-face biometric&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">         <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>ServiceListenerImpl  这个类是负责将回调结果，转发到 FaceManager 中的。通过 IFaceServiceReceiver 的对象，回调 FaceManager 中的 onAuthenticationSucceeded() 方法。<br>FaceManager#onAuthenticationSucceeded()<br><strong>frameworks/base/core/java/android/hardware/face/FaceManager.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="type">IFaceServiceReceiver</span> <span class="variable">mServiceReceiver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">IFaceServiceReceiver</span>.Stub() &#123;</span><br><span class="line">     <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">    <span class="meta">@Override</span> <span class="comment">// binder call</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticationSucceeded</span><span class="params">(<span class="type">long</span> deviceId, Face face, <span class="type">int</span> userId,</span></span><br><span class="line"><span class="params">            <span class="type">boolean</span> isStrongBiometric)</span> &#123;</span><br><span class="line">        mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, isStrongBiometric ? <span class="number">1</span> : <span class="number">0</span>,</span><br><span class="line">                face).sendToTarget();</span><br><span class="line">        <span class="comment">//onFaceidStopped();</span></span><br><span class="line">    &#125;</span><br><span class="line">     <span class="comment">// 省略部分代码 ......</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>在这里通过 mHandler 发送了 MSG_AUTHENTICATION_SUCCEEDED 消息，在 handleMessage 中将会执行 sendAuthenticatedSucceeded() 方法。<br><strong>frameworks/base/core/java/android/hardware/face/FaceManager.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">sendAuthenticatedSucceeded</span><span class="params">(Face face, <span class="type">int</span> userId, <span class="type">boolean</span> isStrongBiometric)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (mAuthenticationCallback != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="type">AuthenticationResult</span> <span class="variable">result</span> <span class="operator">=</span></span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">AuthenticationResult</span>(mCryptoObject, face, userId, isStrongBiometric);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 主要关注这里</span></span><br><span class="line">        mAuthenticationCallback.onAuthenticationSucceeded(result); </span><br><span class="line">        mAuthenticationCallback = <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">if</span>(mPendingFaceAuth != <span class="literal">null</span>) &#123;</span><br><span class="line">            authenticateInternel(mPendingFaceAuth.mCrypto, mPendingFaceAuth.mCancel, mPendingFaceAuth.mFlags, mPendingFaceAuth.mCallback, mPendingFaceAuth.mHandler, mPendingFaceAuth.mUserId);</span><br><span class="line">            mPendingFaceAuth = <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在 sendAuthenticatedSucceeded() 方法中将会执行 BiometricAuthenticator.AuthenticationCallback 的接口的回调，将会把结果回调到 KeyguardUpdateMonitor 中FaceManager.AuthenticationCallback 的onAuthenticationSucceeded() 方法。<br>FaceManager.AuthenticationCallback#onAuthenticationSucceeded()<br>可以看一个堆栈图：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  : java.lang.Throwable</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at com.android.keyguard.KeyguardUpdateMonitor$15.onAuthenticationSucceeded(KeyguardUpdateMonitor.java:1427)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.hardware.face.FaceManager.sendAuthenticatedSucceeded(FaceManager.java:1212)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.hardware.face.FaceManager.access$1300(FaceManager.java:63)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.hardware.face.FaceManager$MyHandler.handleMessage(FaceManager.java:1120)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.os.Handler.dispatchMessage(Handler.java:106)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.os.Looper.loop(Looper.java:223)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.app.ActivityThread.main(ActivityThread.java:7945)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at java.lang.reflect.Method.invoke(Native Method)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)</span><br><span class="line">12-10 16:33:50.024  1414  1414 D longzhiye  :      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)</span><br></pre></td></tr></table></figure>
<p><strong>frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@VisibleForTesting</span></span><br><span class="line">FaceManager.<span class="type">AuthenticationCallback</span> <span class="variable">mFaceAuthenticationCallback</span></span><br><span class="line">        <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FaceManager</span>.AuthenticationCallback() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticationFailed</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 身份验证失败</span></span><br><span class="line">        handleFaceAuthFailed();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/* UNISOC: Modify for bug1374210 &#123;@ */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticationStarted</span><span class="params">()</span> &#123;</span><br><span class="line">        handleFaceAuthStarted();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/* @&#125; */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticationSucceeded</span><span class="params">(FaceManager.AuthenticationResult result)</span> &#123;</span><br><span class="line">        Log.d(<span class="string">&quot;longzhiye&quot;</span>,<span class="string">&quot;longzhiye&quot;</span>,<span class="keyword">new</span> <span class="title class_">Throwable</span>());</span><br><span class="line">        Trace.beginSection(<span class="string">&quot;KeyguardUpdateMonitor#onAuthenticationSucceeded&quot;</span>);</span><br><span class="line">        <span class="comment">// 重点关注</span></span><br><span class="line">        handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());</span><br><span class="line">        Trace.endSection();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticationHelp</span><span class="params">(<span class="type">int</span> helpMsgId, CharSequence helpString)</span> &#123;</span><br><span class="line">        handleFaceHelp(helpMsgId, helpString.toString());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticationError</span><span class="params">(<span class="type">int</span> errMsgId, CharSequence errString)</span> &#123;</span><br><span class="line">        <span class="comment">// 人脸处理操作已取消或未识别到</span></span><br><span class="line">        handleFaceError(errMsgId, errString.toString());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onAuthenticationAcquired</span><span class="params">(<span class="type">int</span> acquireInfo)</span> &#123;</span><br><span class="line">        handleFaceAcquired(acquireInfo);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>KeyguardUpdateMonitor#handleFaceAuthenticated()<br><strong>frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">handleFaceAuthenticated</span><span class="params">(<span class="type">int</span> authUserId)</span> &#123;</span><br><span class="line">    Trace.beginSection(<span class="string">&quot;KeyGuardUpdateMonitor#handlerFaceAuthenticated&quot;</span>);</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="type">int</span> userId;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            userId = ActivityManager.getService().getCurrentUser().id;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (RemoteException e) &#123;</span><br><span class="line">            Log.e(TAG, <span class="string">&quot;Failed to get current user id: &quot;</span>, e);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (userId != authUserId) &#123;</span><br><span class="line">            Log.d(TAG, <span class="string">&quot;Face authenticated for wrong user: &quot;</span> + authUserId);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (isFaceDisabled(userId)) &#123;</span><br><span class="line">            Log.d(TAG, <span class="string">&quot;Face authentication disabled by DPM for userId: &quot;</span> + userId);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">/*重点关注*/</span></span><br><span class="line">        onFaceAuthenticated(userId);</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        setFaceRunningState(BIOMETRIC_STATE_STOPPED);</span><br><span class="line">    &#125;</span><br><span class="line">    Trace.endSection();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>handleFaceAuthenticated#onFaceAuthenticated<br><strong>frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">onFaceAuthenticated</span><span class="params">(<span class="type">int</span> userId)</span> &#123;</span><br><span class="line">    Trace.beginSection(<span class="string">&quot;KeyGuardUpdateMonitor#onFaceAuthenticated&quot;</span>);</span><br><span class="line">    mUserFaceAuthenticated.put(userId, <span class="literal">true</span>);</span><br><span class="line">    <span class="comment">// Update/refresh trust state only if user can skip bouncer</span></span><br><span class="line">    <span class="keyword">if</span> (getUserCanSkipBouncer(userId)) &#123;</span><br><span class="line">        mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FACE);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// Don&#x27;t send cancel if authentication succeeds</span></span><br><span class="line">    mFaceCancelSignal = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; mCallbacks.size(); i++) &#123;</span><br><span class="line">        <span class="comment">/*重点关注*/</span></span><br><span class="line">        <span class="type">KeyguardUpdateMonitorCallback</span> <span class="variable">cb</span> <span class="operator">=</span> mCallbacks.get(i).get();</span><br><span class="line">        <span class="keyword">if</span> (cb != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">/*重点关注*/</span></span><br><span class="line">            cb.onBiometricAuthenticated(userId,</span><br><span class="line">                    BiometricSourceType.FACE);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">   mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE),</span><br><span class="line">            BIOMETRIC_CONTINUE_DELAY_MS);</span><br><span class="line">    <span class="comment">// Only authenticate face once when assistant is visible</span></span><br><span class="line">    mAssistantVisible = <span class="literal">false</span>;</span><br><span class="line">    Trace.endSection();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里开始调用接口将解锁成功消息层层传递直至keyguard解锁，与指纹解锁逻辑一致<br>可以看到在 onFaceAuthenticated(userId) 方法中调用了 KeyguardUpdateMonitorCallback 这个抽象类的 onBiometricAuthenticated() 抽象方法，而 BiometricUnlockController extends KeyguardUpdateMonitorCallback，并且注册了回调 mUpdateMonitor.registerCallback(this)。<br>BiometricUnlockController #onBiometricAuthenticated()<br><strong>frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onBiometricAuthenticated</span><span class="params">(<span class="type">int</span> userId, BiometricSourceType biometricSourceType,</span></span><br><span class="line"><span class="params">        <span class="type">boolean</span> isStrongBiometric)</span> &#123;</span><br><span class="line">    <span class="comment">// 省略部分代码......</span></span><br><span class="line">    <span class="keyword">if</span> (unlockAllowed) &#123;</span><br><span class="line">        mKeyguardViewMediator.userActivity();</span><br><span class="line">        <span class="comment">/*重点关注*/</span></span><br><span class="line">        <span class="comment">// 开始唤醒和解锁</span></span><br><span class="line">        startWakeAndUnlock(biometricSourceType, isStrongBiometric);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        Log.d(TAG, <span class="string">&quot;onBiometricAuthenticated aborted by bypass controller&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>BiometricUnlockController#startWakeAndUnlock<br><strong>frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">startWakeAndUnlock</span><span class="params">(<span class="type">int</span> mode)</span> &#123;</span><br><span class="line">    <span class="comment">// 省略部分代码......</span></span><br><span class="line">    <span class="type">Runnable</span> <span class="variable">wakeUp</span> <span class="operator">=</span> ()-&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (!wasDeviceInteractive) &#123;</span><br><span class="line">            <span class="keyword">if</span> (DEBUG_BIO_WAKELOCK) &#123;</span><br><span class="line">                Log.i(TAG, <span class="string">&quot;bio wakelock: Authenticated, waking up...&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,</span><br><span class="line">                    <span class="string">&quot;android.policy:BIOMETRIC&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (delayWakeUp) &#123;</span><br><span class="line">           <span class="comment">/*重点关注*/</span></span><br><span class="line">            mKeyguardViewMediator.onWakeAndUnlocking();</span><br><span class="line">        &#125;</span><br><span class="line">        Trace.beginSection(<span class="string">&quot;release wake-and-unlock&quot;</span>);</span><br><span class="line">        releaseBiometricWakeLock();</span><br><span class="line">        Trace.endSection();</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="comment">// 省略部分代码......</span></span><br><span class="line">    mStatusBar.notifyBiometricAuthModeChanged();</span><br><span class="line">    Trace.endSection();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>KeyguardViewMediator#onWakeAndUnlocking()<br><strong>frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onWakeAndUnlocking</span><span class="params">()</span> &#123;</span><br><span class="line">    Trace.beginSection(<span class="string">&quot;KeyguardViewMediator#onWakeAndUnlocking&quot;</span>);</span><br><span class="line">    mWakeAndUnlocking = <span class="literal">true</span>;</span><br><span class="line">    <span class="comment">/*重点关注*/</span></span><br><span class="line">    keyguardDone();</span><br><span class="line">    Trace.endSection();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>KeyguardViewMediator#keyguardDone()<br><strong>frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">keyguardDone</span><span class="params">()</span> &#123;</span><br><span class="line">    Trace.beginSection(<span class="string">&quot;KeyguardViewMediator#keyguardDone&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (DEBUG) Log.d(TAG, <span class="string">&quot;keyguardDone()&quot;</span>);</span><br><span class="line">    userActivity();</span><br><span class="line">    EventLog.writeEvent(<span class="number">70000</span>, <span class="number">2</span>);</span><br><span class="line">    <span class="comment">/*重点关注*/</span></span><br><span class="line">    <span class="type">Message</span> <span class="variable">msg</span> <span class="operator">=</span> mHandler.obtainMessage(KEYGUARD_DONE);</span><br><span class="line">    mHandler.sendMessage(msg);</span><br><span class="line">    Trace.endSection();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>keyguardDone()该方法发送了一条 KEYGUARD_DONE 消息，在 handleMessage 中将会执行 handleKeyguardDone() 方法。<br>KeyguardViewMediator#handleKeyguardDone()<br><strong>frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">handleKeyguardDone</span><span class="params">()</span> &#123;</span><br><span class="line">    Trace.beginSection(<span class="string">&quot;KeyguardViewMediator#handleKeyguardDone&quot;</span>);</span><br><span class="line">    <span class="keyword">final</span> <span class="type">int</span> <span class="variable">currentUser</span> <span class="operator">=</span> KeyguardUpdateMonitor.getCurrentUser();</span><br><span class="line">    <span class="comment">// 省略部分代码......</span></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * 重点关注</span></span><br><span class="line"><span class="comment">     * 处理隐藏</span></span><br><span class="line"><span class="comment">    **/</span></span><br><span class="line">    handleHide();</span><br><span class="line">    Trace.endSection();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>KeyguardViewMediator# handleHide()<br><strong>frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">handleHide</span><span class="params">()</span> &#123;</span><br><span class="line">    Trace.beginSection(<span class="string">&quot;KeyguardViewMediator#handleHide&quot;</span>);</span><br><span class="line">    <span class="comment">// It&#x27;s possible that the device was unlocked in a dream state. It&#x27;s time to wake up.</span></span><br><span class="line">    <span class="keyword">if</span> (mAodShowing) &#123;</span><br><span class="line">        <span class="type">PowerManager</span> <span class="variable">pm</span> <span class="operator">=</span> mContext.getSystemService(PowerManager.class);</span><br><span class="line">        pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,</span><br><span class="line">                <span class="string">&quot;com.android.systemui:BOUNCER_DOZING&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">synchronized</span> (KeyguardViewMediator.<span class="built_in">this</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (DEBUG) Log.d(TAG, <span class="string">&quot;handleHide&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (mustNotUnlockCurrentUser()) &#123;</span><br><span class="line">         </span><br><span class="line">            <span class="keyword">if</span> (DEBUG) Log.d(TAG, <span class="string">&quot;Split system user, quit unlocking.&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        mHiding = <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">if</span> (mShowing &amp;&amp; !mOccluded) &#123;</span><br><span class="line">            mKeyguardGoingAwayRunnable.run();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">/*重点关注*/</span></span><br><span class="line">            <span class="comment">// 处理开始键盘保护退出动画</span></span><br><span class="line">            handleStartKeyguardExitAnimation(</span><br><span class="line">                    SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),</span><br><span class="line">                    mHideAnimation.getDuration());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    Trace.endSection();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>KeyguardViewMediator#handleStartKeyguardExitAnimation()<br><strong>frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">handleStartKeyguardExitAnimation</span><span class="params">(<span class="type">long</span> startTime, <span class="type">long</span> fadeoutDuration)</span> &#123;</span><br><span class="line">    Trace.beginSection(<span class="string">&quot;KeyguardViewMediator#handleStartKeyguardExitAnimation&quot;</span>);</span><br><span class="line">    <span class="comment">// 省略部分代码......</span></span><br><span class="line">        mWakeAndUnlocking = <span class="literal">false</span>;</span><br><span class="line">        setShowingLocked(<span class="literal">false</span>, mAodShowing);</span><br><span class="line">        mDismissCallbackRegistry.notifyDismissSucceeded();</span><br><span class="line">        <span class="comment">/*重点关注*/</span></span><br><span class="line">        mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);</span><br><span class="line">        resetKeyguardDonePendingLocked();</span><br><span class="line">        mHideAnimationRun = <span class="literal">false</span>;</span><br><span class="line">        adjustStatusBarLocked();</span><br><span class="line">        sendUserPresentBroadcast();</span><br><span class="line">    &#125;</span><br><span class="line">    Trace.endSection();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>下面就不详细分析了，将会按如下顺序执行：StatusBarKeyguardViewManager#hide()→StatusBarKeyguardViewManager#hideBouncer()→KeyguardBouncer#hide()→KeyguardBouncer#mRemoveViewRunnable→KeyguardBouncer#removeView()。</p>

      
      <blockquote>
        
        <strong>本文链接：</strong><br><a href="http://longzhiye.top/2023/12/10/2023-12-10/">http://longzhiye.top/2023/12/10/2023-12-10/</a>
      </blockquote>
    </div>
    <footer class="mdui-card-actions">
      
        <a class="mdui-ripple article_categories-link" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a>
      
      
        <a class="mdui-ripple article_tags-link" href="/tags/Android/" rel="tag">Android</a><a class="mdui-ripple article_tags-link" href="/tags/Launcher/" rel="tag">Launcher</a><a class="mdui-ripple article_tags-link" href="/tags/SystemUI/" rel="tag">SystemUI</a><a class="mdui-ripple article_tags-link" href="/tags/framework/" rel="tag">framework</a>
      
    </footer>
    
  </article>
  
<script src="//cdn.bootcdn.net/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdn.bootcdn.net/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js"></script>

  <script>$("#main article .mdui-card-content img.fancybox").on("click",function(e){$.fancybox.open({src:$(this).attr("src")});});</script>


  <nav id="paginator">
    
      <a rel="prev" class="extend prev" href="/2023/12/16/2023-12-16/">
        <button aria-label="prev" class="mdui-btn mdui-btn-raised mdui-btn-icon mdui-color-theme-accent mdui-ripple"><i class="mdui-icon material-icons">arrow_back</i></button>
        <span class="mdui-p-x-3" mdui-tooltip="{content: 'Android 10.0 截屏流程'}">上一篇</span>
      </a>
    
    <div class="spacer"></div>
    
      <a rel="next" class="extend next" href="/2023/12/09/2023-12-09/">
        <span class="mdui-p-x-3" mdui-tooltip="{content: 'Android10.0 锁屏分析-KeyguardPatternView图案锁分析'}">下一篇</span>
        <button aria-label="next" class="mdui-btn mdui-btn-raised mdui-btn-icon mdui-color-theme-accent mdui-ripple"><i class="mdui-icon material-icons">arrow_forward</i></button>
      </a>
    
  </nav>





</main>
  <footer id="footer" class="mdui-m-t-5 mdui-p-y-3 mdui-color-theme">
  <div class="mdui-p-y-0 mdui-text-center">
    
    
    
    
    
    
    
      <a href="http://github.com/longzhiye" target="_blank" class="mdui-btn mdui-btn-icon mdui-text-color-theme-a100"><i class="mdui-icon iconfont">&#xe7ab;</i></a>
    
    
    
      <a href="https://www.zhihu.com/people/long-zhi-xie-61" target="_blank" class="mdui-btn mdui-btn-icon mdui-text-color-theme-a100"><i class="mdui-icon iconfont">&#xe6c0;</i></a>
    
    
    
      <a href="tencent://tencent:////message/?uin=951898105&Menu=yes" target="_blank" class="mdui-btn mdui-btn-icon mdui-text-color-theme-a100"><i class="mdui-icon iconfont">&#xe651;</i></a>
    
    
  </div>
  <div class="mdui-p-y-1 mdui-text-center">
    Copyright &copy; 2022 - 2025 龙之叶<br>
    Powered by <a href="https://hexo.io/" target="_blank" class="mdui-text-color-theme-accent">Hexo</a>
    <br>
      <span id="busuanzi_container_site_pv" style="display: none;"><i class="iconfont">&#xe7fd;</i> <span id="busuanzi_value_site_pv"></span></span> &nbsp;&nbsp;
      <span id="busuanzi_container_site_uv" style="display: none;"><i class="iconfont">&#xe601;</i> <span id="busuanzi_value_site_uv"></span></span>
    
  </div>
</footer>

  <button id="gotop" class="mdui-fab mdui-fab-fixed mdui-fab-hide mdui-color-theme-accent mdui-ripple"><i class="mdui-icon material-icons">arrow_upward</i></button>
  <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
  
<script src="/js/mdui.js"></script>
<script src="/js/script.js"></script>

  
<script src="/custom.js"></script>

</body>
</html>
